'''
【说明】利用Graphviz模块的Digraph工具集来实现对语法分析树的可视化展示 接收语法分析树needTree作输入 创建绘图脚本TreeScript 并绘制图像


###数据结构###
【tokens】详情见Lex.py
【needTree】详情见Expr.py
【tag_tokens】详情见Expr.py (tag取值扩展了上述语法单元名)
'''

'''
函数表
  |-drawTree(tree)   初始化绘图的文件信息及句柄对象 调用节点绘图函数 并导出图片
    |-drawTreePoint(tree, dot, parentId, currentId)   绘制树节点与连线
    |-getRandId()  生成随机id(8位时间戳拼接7位随机整数)用作节点名称
    |-getTextFromTokens() 将token序列中的token的文本串联 生成节点填充信息
  '''


from graphviz import Digraph
import time
import random


#drawTree()绘制树 并打印
#tree 表示树的字典结构 
def drawTree(tree):
  dot = Digraph(name="Tree", format="png")
  drawTreePoint(tree,dot,-1,getRandId())
  dot.render(filename="Tree")



#drawTreePoint()绘制树节点以及连线
#tree 表示树的字典结构 
#dot  绘图对象  初始传入为None
#parentId 树父亲节点的编号 初代为-1
#currentId 当前节点的编号 时间戳随机ID 唯一性
def drawTreePoint(tree,dot,parentId,currentId):
  #绘制树根
  if parentId == -1:
      treeRootText=getTextFromTokens((tree["root"][1]))
      typeText="  =>"+tree["root"][0]
      dot.node(currentId,treeRootText+typeText)
      for key in sorted(tree.keys()):
        if key!="root":
          drawTreePoint(tree[key],dot,currentId,getRandId())
      return 
  #1.若空节点 不做操作
  if tree is None:
    return
  #2.若为列表类型 则属于叶节点
  if isinstance(tree,list):
    # print(tree)
    treeText=getTextFromTokens(tree[1])
    typeText="  => "+tree[0]
    dot.node(currentId,treeText+typeText)
    dot.edge(parentId,currentId)
    return
  #3.若是子树
  if isinstance(tree, dict):
    #3.1若子树根是空的 则跳过该子树
    if tree["root"] is None:
      return
    #3.2若子树有根 则先绘制根节点 并将根节点与父亲节点连线 并递归调用绘制三个子叶  
    else:
      treeRootText=getTextFromTokens((tree["root"][1]))
      typeText="  =>"+tree["root"][0]
      dot.node(currentId,treeRootText+typeText)
      dot.edge(parentId,currentId)
      for key in sorted(tree.keys()):
        if key!="root":
          drawTreePoint(tree[key],dot,currentId,getRandId())
      return

#getRandId()生成随机节点Id
def getRandId():
  timeStr= str(int(round(time.time() * 1000)))[-8:]
  randomStr=""
  for i in range(7):
    randomStr+=str(random.randint(1,9))
  return timeStr+randomStr

#getTextFromTokens() 从一组token序列中获取content并连成字符串 用作节点信息填充
def getTextFromTokens(tokens):
  text=""
  for item in tokens:
    if item[0]==4 and item[1]in["int","else"]:
      text=text+item[1]+" "
    else:
      text=text+item[1]
  return text